package xin.xihc.lottery.dao;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.ui.Model;
import xin.xihc.jba.core.JbaTemplate;
import xin.xihc.jba.core.PageInfo;
import xin.xihc.jba.core.utils.JbaLog;
import xin.xihc.jba.demo.ABaseModel;
import xin.xihc.jba.scan.TableManager;
import xin.xihc.jba.scan.tables.properties.ColumnProperties;
import xin.xihc.jba.scan.tables.properties.TableProperties;
import xin.xihc.jba.sql.Select;
import xin.xihc.jba.sql.Update;
import xin.xihc.jba.sql.Where;
import xin.xihc.jba.sql.clause.Eq;
import xin.xihc.jba.sql.clause.EqSelf;
import xin.xihc.lottery.model.AModel;

import java.beans.PropertyDescriptor;
import java.lang.reflect.ParameterizedType;
import java.util.*;

/**
 * 最顶级Dao层,只需继承即可完成基础操作,抽象类
 *
 * @author Leo.Xi
 * @version 1.0
 * @date 2022/2/26 12:53
 * @since 1.0
 */
public abstract class ADao<T extends AModel> {

    /** 数据库操作Template */
    @Autowired
    @Qualifier("jbaTemplate")
    protected JbaTemplate jbaTemplate;

    /** 日志记录器 */
    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    /** T -> Class */
    protected Class<T> tClass;

    public ADao() {
        this.tClass = getTClass();
    }

    /**
     * 获取泛型T的Class
     *
     * @return Class<T>
     */
    @SuppressWarnings("unchecked")
    protected Class<T> getTClass() {
        return (Class<T>) (((ParameterizedType) this.getClass()
                                                    .getGenericSuperclass()).getActualTypeArguments()[0]);
    }

    /**
     * 添加操作
     *
     * @param record 插入的数据
     * @return 是否插入成功（true-成功）
     */
    public boolean add(T record) {
        Objects.requireNonNull(record, "record is null");

        return jbaTemplate.insertModel(record);
    }

    /**
     * 批量添加,每50个插入一次
     *
     * @param records 插入到数据数组
     */
    public void batchAdd(T[] records) {
        Objects.requireNonNull(records, "records is null");

        if (records.length < 1) {
            return;
        }

        List<T> temp = new LinkedList<>();

        for (T record : records) {
            temp.add(record);

            if (temp.size() >= 50) {
                jbaTemplate.insertModels(temp.toArray());
                temp.clear();
            }
        }

        if (temp.size() > 0) {
            jbaTemplate.insertModels(temp.toArray());
        }
        temp.clear();
        temp = null;
    }

    /**
     * 更新操作
     *
     * @param record 更新内容
     * @return 是否更新成功（true-成功）
     */
    public boolean updateById(T record) {
        Objects.requireNonNull(record, "record is null");
        Objects.requireNonNull(record.getId(), "no id");

        return jbaTemplate.updateModel(record, "id");
    }

    /**
     * 安全的更新 - 乐观锁
     *
     * @param record 表实体
     * @author Leo.Xi
     * @date 2020/8/12
     * @since 0.0.1
     */
    public boolean updateByIdSafe(T record) {
        Objects.requireNonNull(record, "record is null");
        Objects.requireNonNull(record.getId(), "no id");
        Objects.requireNonNull(record.getVersion(), "no version");

        TableProperties tableProperties = TableManager.getTable(record.getClass());
        LinkedHashMap<String, ColumnProperties> columns = tableProperties.getColumns();
        Update update = Update.from(record.getClass());
        Where where = update.where();

        where.and(new Eq("id", record.getId()));
        update.set(new EqSelf("version", 1));

        for (String field : columns.keySet()) {
            if ("version".equals(field)) {
                continue;
            }
            try {
                PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor(record.getClass(), field);
                Object value = propertyDescriptor.getReadMethod()
                                                 .invoke(record);
                if (value != null) {
                    update.set(new Eq(columns.get(field)
                                             .colName(), value));
                }
            } catch (Exception e) {
                JbaLog.error(e);
            }
        }

        return jbaTemplate.update(update);
    }

    /**
     * 批量执行sql
     *
     * @param sql    sql语句
     * @param params 参数
     */
    public void batchUpdate(final String sql, Map<String, ?>[] params) {
        jbaTemplate.batchUpdate(sql, params);
    }

    /**
     * 根据ID单个查询
     *
     * @param id ID
     * @return tClass
     */
    public T findById(final Integer id) {
        return findById(id, this.tClass);
    }

    /**
     * 根据ID单个查询,返回制定类型
     *
     * @param id    ID
     * @param clazz 响应类型
     * @return clazz
     */
    public <E> E findById(final Integer id, Class<E> clazz) {
        if (id == null) {
            return null;
        }
        try {
            T t = this.tClass.newInstance();
            t.setId(id);
            return jbaTemplate.queryModelOne(t, clazz);
        } catch (Exception e) {
            logger.error("findById():", e);
        }
        return null;
    }

    /**
     * 根据ID删除
     *
     * @param id ID
     * @return 是否删除成功（true-成功）
     */
    public boolean deleteById(final Integer id) {
        if (id == null) {
            return false;
        }
        T t = null;
        try {
            t = this.tClass.newInstance();
            t.setId(id);
            return delete(t);
        } catch (Exception e) {
            logger.error("deleteById():", e);
        }
        return false;
    }

    /**
     * 根据对象删除
     *
     * @param record 删除条件
     * @return 是否删除成功（true-成功）
     */
    public boolean delete(T record) {
        return jbaTemplate.deleteModel(record);
    }

    /**
     * 分页查询
     *
     * @param pageInfo 分页信息
     * @param record   查询条件
     * @param orderBy  排序（属性名或表列名）
     * @return List
     */
    public List<T> page(T record, PageInfo pageInfo, String... orderBy) {
        Objects.requireNonNull(record, "record is null");
        if (orderBy.length < 1) {
            orderBy    = new String[1];
            orderBy[0] = "create_time DESC";
        }
        return jbaTemplate.queryModelList(record, this.tClass, pageInfo, orderBy);
    }

    /**
     * 分页查询
     *
     * @param pageInfo 分页信息
     * @param clazz    响应对象类型
     * @param record   查询条件
     * @param orderBy  排序（属性名或表列名）
     * @return List
     */
    public <E> List<E> page(T record, Class<E> clazz, PageInfo pageInfo, String... orderBy) {
        Objects.requireNonNull(record, "record is null");
        if (orderBy.length < 1) {
            orderBy    = new String[1];
            orderBy[0] = "create_time DESC";
        }
        return jbaTemplate.queryModelList(record, clazz, pageInfo, orderBy);
    }

    /**
     * 查询数量
     *
     * @param record 条件对象
     * @return 数量
     */
    public int count(T record) {
        Objects.requireNonNull(record, "record is null");

        return jbaTemplate.queryCount(record);
    }

    /**
     * 查询是否存在
     *
     * @param record 表对象
     * @return true - 存在；false - 不存在
     */
    public boolean exists(T record) {
        Objects.requireNonNull(record, "record is null");

        return count(record) > 0;
    }

    // ------ 1.8.5 新增方法 ------

    /**
     * 查询数据库--Select
     *
     * @param select   Select对象
     * @param clazz    返回的类型
     * @param pageInfo 分页信息
     * @return 列表
     * @since 1.8.5
     */
    public <T> List<T> queryList(Select select, Class<T> clazz, PageInfo pageInfo) {
        return jbaTemplate.queryList(select, clazz, pageInfo);
    }

    /**
     * 查询数据库--Select单个查询
     *
     * @param select Select对象
     * @param clazz  返回的类型
     * @return 单个实体
     * @since 1.8.5
     */
    public <T> T queryOne(Select select, Class<T> clazz) {
        return jbaTemplate.queryOne(select, clazz);
    }

    /**
     * 执行sql语句 - Update对象
     *
     * @param update Update对象
     * @return 是否执行成功
     * @since 1.8.5
     */
    public boolean update(Update update) {
        return jbaTemplate.update(update);
    }

}
